package cn.seaboot.admin.api.mapping;

import cn.seaboot.admin.api.bean.ApiAction;
import cn.seaboot.admin.api.bean.ApiMapping;
import cn.seaboot.admin.api.bean.ApiParameter;
import cn.seaboot.admin.api.service.ApiActionService;
import cn.seaboot.admin.api.service.ApiMappingService;
import cn.seaboot.admin.api.service.ApiParameterService;
import cn.seaboot.commons.core.CommonUtils;
import cn.seaboot.openapi.base.ControllerInfo;
import cn.seaboot.openapi.base.MethodInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * 扫描一个方法上的映射配置
 *
 * @author Mr.css
 * @version 2022-04-18 11:41
 */
@Component
public class ApiMappingManager {
    private final Logger logger = LoggerFactory.getLogger(ApiMappingManager.class);

    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private ApiActionService apiActionService;

    @Resource
    private ApiMappingService apiMappingService;

    @Resource
    private ApiParameterService apiParameterService;

    @Resource
    private ControllerScanner controllerScanner;

    @Resource
    private MappingScanner mappingScanner;

    @Resource
    private ParameterScanner parameterScanner;

    /**
     * 清理所有数据
     *
     * @param projectId 工程ID
     */
    public void cleanAPI(String projectId) {
        apiActionService.deleteByProjectId(projectId);
        apiMappingService.deleteByProjectId(projectId);
        apiParameterService.deleteByProjectId(projectId);
    }

    /**
     * 扫描整个工程的所有Controller
     *
     * @param projectId 项目ID
     */
    public void scanAPI(String projectId) {
        // 扫描所有的Controller
        Map<String, Object> controllers = applicationContext.getBeansWithAnnotation(Controller.class);
        if (CommonUtils.isNotEmpty(controllers)) {
            for (Object controller : controllers.values()) {
                logger.info("scan controller api:" + controller);
                this.scanControllerInfo(projectId, controller.getClass());
            }
        }

        // 扫描所有的RestController
        controllers = applicationContext.getBeansWithAnnotation(RestController.class);
        if (CommonUtils.isNotEmpty(controllers)) {
            for (Object controller : controllers.values()) {
                logger.info("scan rest-controller api:" + controller);
                this.scanControllerInfo(projectId, controller.getClass());
            }
        }
    }

    /**
     * 扫描Controller
     *
     * @param projectId  项目ID
     * @param controller Controller 的 class
     */
    public void scanControllerInfo(String projectId, Class<?> controller) {
        // 忽略内置的 Controller
        if (ignore(controller)) {
            logger.info("ignore controller: {}", controller);
            return;
        }

        // 空的 Controller
        ControllerInfo controllerInfo = new ControllerInfo(controller);
        List<MethodInfo> methodInfos = controllerInfo.getMethodInfos();
        if (CommonUtils.isEmpty(methodInfos)) {
            logger.info("{} not contain method!", controller);
            return;
        }

        // 分组信息，一个 Controller 定为一组
        ApiAction apiAction = controllerScanner.scanControllerInfo(projectId, controllerInfo);
        apiActionService.insert(apiAction);

        // 扫描所有的方法
        for (MethodInfo methodInfo : methodInfos) {
            // 接口映射信息
            List<ApiMapping> mappings = mappingScanner.scanApiMapping(apiAction, controllerInfo, methodInfo);
            apiMappingService.insertBatch(mappings);

            // 接口参数信息
            for (ApiMapping mapping : mappings) {
                List<ApiParameter> parameters = parameterScanner.scanMethodParameter(mapping, controllerInfo, methodInfo);
                for (ApiParameter parameter : parameters) {
                    apiParameterService.insert(parameter);
                }
            }
        }
    }

    /**
     * 忽略一些系统内置的Controller
     *
     * @param controller class
     * @return boolean
     */
    private boolean ignore(Class<?> controller) {
        String ctl = controller.getName();
        return ctl.startsWith("org.springframework") || ctl.startsWith("javax");
    }
}
